const PENDING = 'pending', FULFILLED = 'fulfilled', REJECTED = 'rejected'
class YGPromise {
    constructor(excutor) {
        try {
            excutor(this.resolve, this.reject)   
        } catch (error) {
            this.reject(error)
        }
    }
    value = null
    reason = null
    state = PENDING
    onFulfilledCbs = []
    onRejectedCbs = []

    resolve = value => {
        if (this.state === PENDING) {
            this.value = value
            this.state = FULFILLED
        }
    }
    reject = reason => {
        if (this.state === PENDING) {
            this.reason = reason
            this.state = REJECTED
        }
    }
    then = (onFulfilled, onRejected) => {
        onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value
        onRejected = typeof onRejected === 'function' ? onRejected: reason => reason
        const p = new YGPromise((resolve, reject) => {
            const fulfillMicrotask = () => {
                try {
                    queueMicrotask(() => {
                        const x = onFulfilled(this.value)
                        onResolvePromise(p, x, resolve, reject)
                    })
                } catch (error) {
                    reject(error)
                }
            }
            const rejectMicrotask = () => {
                try {
                    queueMicrotask(() => {
                        const x = onRejected(this.reason)
                        onResolvePromise(p, x, resolve, reject)
                    })
                } catch (error) {
                    reject(error)
                }
            }
            if (this.state === FULFILLED) {
                fulfillMicrotask()
            } else if (this.state === REJECTED) {
                rejectMicrotask()
            } else {
                this.onFulfilledCbs.push(fulfillMicrotask)
                this.onRejectedCbs.push(rejectMicrotask)
            }
        })
        return p
    }
    static resolve = function(params) {
        if (params instanceof YGPromise) {
            return params
        } else {
            return new YGPromise((resolve, reject) => {
                resolve(params)
            })
        }
    }
    static reject = function(params) {
        return new YGPromise((resolve, reject) => {
            reject(params)
        })
    }
}

function onResolvePromise(p, x, resolve, reject) {
    if (x instanceof YGPromise) {
        if (x === p) {
            throw new TypeError('promise cycle error')
        } else {
            x.then(resolve, reject)
        }
    } else {
        resolve(this.value)
    }
}

const p = new YGPromise((resolve, reject) => {
    // resolve('resolve success')
    // reject('rejecte err')
    setTimeout(() => {
        resolve('resolve success')
    }, 2000);
})
p.then(
    value => {
        console.log(value)
        return new YGPromise((resolve, reject) => {
            resolve('other promise resolve success')
        })
    },
    reason => {
        console.log(reason)
    }
).then( 
    value => {
        console.log(value)
    },
    reason => {
        console.log(reason)
    }
)

YGPromise.resolve('1').then(
    value => {
        return 123
    }
).then(value => console.log(value))
YGPromise.reject('2 err').then(
    value => console.log(value),
    reason => console.log(reason)
)